#! /usr/bin/python
# -*- coding: utf-8 -*-
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#
# Functions used by qview
#_________________________________________________________
# A.Z. - 10/07 => Creation
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
import os
import sys
import optparse
import numpy
from pylab import *
from globalVariables import gv
from displayImage import DisplayImage
from dataFileReader import DataFileReader



#-------------------------------------------------------------------------------
def Abort(msg):
  """
  Aborts the program and prints a message to stderr
  """
  sys.stderr.write("!!  "+msg+"\n")
  sys.exit()




#-------------------------------------------------------------------------------
def getUsage():
  """
  Returns the program usage.
  """
  u ="\n"
  u+=" Examples:\n"
  u+="     qview -f lc.dat\n"
  u+="     qview -f lc.dat -t 2\n"
  u+="     qview -f lc.dat -t 2 -c 3 -c 4\n"
  u+="     qview -f lc.dat -t 2 -c 3:4 (same as above)\n"  
  u+="     qview -f lc.dat -e editable.py -t 2 -c 3 -c 4\n"
  u+="     qview -f lc.dat -i lc.fits.lis -t 2 -c 3 -c 4\n"
  u+="     qview -f lc.dat -e editable.py -i lc.fits.lis -t 2 -c 3 -c 4\n"
  return u

def usage():
  """
  Prints the program usage and exit.
  """
  sys.stderr.write(getUsage())
  sys.exit()



#-------------------------------------------------------------------------------
def parseCommandLineArguments():
  """
  Parses the command line arguments in sys.argv and save the results in the
  GlobalVariables instance
  """

  parser = optparse.OptionParser(prog="qview", version="0.1",
                                 description="qview - quick lightcurve viewer",
                                 usage="qview -f lc.dat [options]\n"+getUsage())

  filesGroup = optparse.OptionGroup(parser, "Lightcurve, images and editable files", "")
  
  filesGroup.add_option("-f", "--file", action="store", dest="filename", type="string",
                        help="load light curve from FILE", metavar="FILE")

  filesGroup.add_option("-i", "--images", action="store", dest="imagesList", type="string",
                        help="load image list from FILE to associate each light curve point to a FITS file.",
                        metavar="FILE")

  filesGroup.add_option("-e", "--editable", action="store", dest="editable", type="string",
                        help="load editable script from FILE", metavar="FILE")

  columnGroup = optparse.OptionGroup(parser, "Columns definition", "")

  columnGroup.add_option("-c", "--column", action="append", dest="countsColumn", type="string",
                         help="plot the given COLUMNS. COLUMNS could be a single integer or a range, "
                         "using : (colon) as separator, as 1:5, to plot columns 1 to 5. "
                         "You can also combine ranges or single columns using a coma, like "
                         "1,2,5:10 to plot columns 1, 2 and from 5 to 10. "
                         "You can use this option multiple times. default=all columns.",
                         metavar="COLUMNS")

  columnGroup.add_option("-t", "--time", action="store", dest="timeColumn", type="int",
                         help="use COLUMN as time (x-axis) in the plot (default=%default).",
                         metavar="COLUMN")

  parser.add_option_group(filesGroup)
  parser.add_option_group(columnGroup)  

  parser.set_defaults(filename     = "",
                      imagesList   = "",
                      editable     = "",
                      timeColumn   = 1,
                      countsColumn = [])
  
  options, args = parser.parse_args(sys.argv)

  # convert from optparse to gv
  gv.fileName = options.filename
  gv.editable = options.editable

  if options.imagesList:
    gv.display  = DisplayImage(options.imagesList)

  gv.tCol = options.timeColumn
  gv.yCol = parseColumnRange(options.countsColumn)
  gv.ofile    = os.path.basename( gv.fileName ) + ".changed"
  gv.odftfile = os.path.basename( gv.fileName ) + ".dft"

  # only required argument is filename, so if not given, give up and shout.
  if not gv.fileName:
    parser.print_help()
    sys.exit(1)



#-------------------------------------------------------------------------------
def parseColumnRange(columns):
  """
  Parse column ranges specification from command line options and
  returns a list with desired column indexes.
  """

  yCol = []

  for column in columns:
    parts = column.split(",")

    for part in parts:
      # simple column
      if not ":" in part:
        try:
          yCol.append(int(part.strip()))
        except ValueError:
          pass
      # ranges
      else:
        begin, end = part.split(":")
        try:
          yCol.extend([i for i in range(int(begin.strip()), int(end.strip())+1)])
        except ValueError:
          pass
      
  return yCol


  
#-------------------------------------------------------------------------------
def readLightCurveFile():
  """
  Reads the light curve file ignoring both commentary and empty lines.
  Returns numpy arrays with the data.
  """
  # Read the data file
  dfr = DataFileReader()
  F = numpy.array( dfr.read(gv.fileName) )

  # Gets the right columns for each parameters
  F = F.transpose()
  Ncf = len(F)       # Number of columns IN THE FILE

  # use all columns if none given on command line
  if not gv.yCol:
    gv.yCol = range(2, Ncf+1)
    
  Nc  = len(gv.yCol) # Number of columns TO GET in the file

  msg="The file \""+gv.fileName+"\" doesn't have the column number %d."

  # Read the time
  # Assume Julian Date input and convert to seconds from the first point
  if gv.tCol>Ncf: Abort( msg % gv.tCol )
  gv.tjd = numpy.array( F[gv.tCol-1], dtype=str )
  gv.nt  = len(gv.tjd)
  gv.t   = numpy.zeros(gv.nt)
  for i in range(1,gv.nt):
    gv.t[i] = 24*60*60*( float(gv.tjd[i]) - float(gv.tjd[0]) )

  # Read the counts
  gv.y = numpy.zeros( ( Nc, gv.nt ) )
  for c in range(0,Nc):
    if gv.yCol[c]>Ncf: Abort( msg % gv.yCol[c] )
    gv.y[c] = numpy.array( F[gv.yCol[c]-1], dtype=float )
  gv.ny = len(gv.y)




#-------------------------------------------------------------------------------
def readEditable(locals=None,globals=None):
  """
  Executes the file gv.editable
  """
  # Copy of the unedited vector
  gv.Cy = numpy.copy(gv.y)

  # Load and execute the file where the user made his editions
  if gv.editable!="":
    exec compile(open(gv.editable).read(), gv.editable,"exec") in locals,globals




#-------------------------------------------------------------------------------
def plotAll(plotDFT=False,keyEvent=None):
  """
  Executes the editable file and plot the data
  """
  readEditable()

  if plotDFT:
    setFrequencies()      # Sets the frequencies using Nyquist values
    dft()                 # Fourier Transform of gv.Cy without deleted points


  # Remove the deleted points and save them to show with different colors
  Cyd = []                  # Just the deleted points
  yd  = []        
  for i in range(0,gv.ny):
    yd.append ( numpy.take( gv.y[i] ,gv.delete) )
    Cyd.append( numpy.take( gv.Cy[i],gv.delete) )
  td = numpy.take( gv.t, gv.delete )


  # Plot the original (unedited) data
  figure(1)
  lim = axis()
  for i in range(0,gv.ny):
    gv.SO[i].hold(False)              # Clear the plot before replotting
    gv.SO[i].plot( gv.t , gv.y[i] , 'ob' )
    gv.SO[i].hold(True)
    gv.SO[i].hold(True)               # Don't clear again
    gv.SO[i].plot( td, yd[i], 'or' )  # Just the deleted points    (red)
    if i<gv.ny-1: setp( gv.SO[i].get_xticklabels(), visible=False)
  ion()
  if not gv.firstPlot: axis( lim )
  if keyEvent!=None and gv.figure==1: gv.CO[gv.axes].onmove(keyEvent)


  # Plot the edited data
  figure(2)
  lim = axis()
  for i in range(0,gv.ny):
    gv.SE[i].hold(False)              # Clear the plot before replotting
    gv.SE[i].plot( gv.t , gv.Cy[i] , 'ob' )  
    gv.SE[i].hold(True)               # Don't clear again
    gv.SE[i].plot( td, Cyd[i], 'or' )  # Just the deleted points    (red)
    if i<gv.ny-1: setp( gv.SE[i].get_xticklabels(), visible=False)
  ion()
  if not gv.firstPlot: axis( lim )
  if keyEvent!=None and gv.figure==2: gv.CE[gv.axes].onmove(keyEvent)


  # Plot the FT data
  if gv.firstPlot or plotDFT:
    figure(3)
    lim = axis()
    for i in range(0,gv.ny):
      gv.SD[i].hold(False)              # Clear the plot before replotting
      gv.SD[i].plot( gv.f , gv.dft[i] , 'ob' )  
      gv.SD[i].hold(True)               # Don't clear again
      if i<gv.ny-1: setp( gv.SD[i].get_xticklabels(), visible=False)
    ion()
    if not gv.firstPlot: axis( lim )
    if keyEvent!=None and gv.figure==3: gv.CD[gv.axes].onmove(keyEvent)


  if gv.firstPlot:
    gv.firstPlot=False
  



#-------------------------------------------------------------------------------
def setFrequencies():
  """
  If the values aren't set, use the timings to set the frequencies of the
  discrete fourier transform according to:
   fmin = 1.0/( Ttotal      )  -->  1 over the total observation time
   fmax = 1.0/( 2.0*min(dt) )  -->  Pseudo-Nyquist frequency for not evenly
                                    spaced data.
   Nf                          -->  5 * Number of data points
  """
  # Set the values if they are "None", otherwise, use the pre-defined values
  if gv.nf==None  : gv.nf   = 5 * gv.nt
  if gv.fmin==None: gv.fmin = 1.0/( gv.t[gv.nt-1] - gv.t[0] )

  if gv.fmax==None:
    mindt=gv.t[1]-gv.t[0]
    for i in range(2,gv.nt):
      aux = gv.t[i]-gv.t[i-1]
      if aux<mindt:
        mindt=aux
      gv.fmax = 1.0/( 2.0*mindt )

  if gv.fmin>=gv.fmax or gv.fmin<0 or gv.fmax<0:
    msg = "Wrong frequencies. Check your time data! Are they sorted? "
    msg+= "Are there repeated values?"
    Abort(msg)

  df = (gv.fmax-gv.fmin)/(gv.nf-1.0)
  gv.f = []
  gv.f.append(gv.fmin)
  for i in range(1,gv.nf):
    gv.f.append( gv.f[i-1]+df )
  



#-------------------------------------------------------------------------------
def dft():
  """
  It's written to be as fast as possible.
  I've used numpy ufuncs. If you don't use them, this function becomes
  EXTREMELY slow!
  Maybe I'll have to write it in C later but I'm satisfied now.
  """
  t  = numpy.delete( gv.t, gv.delete ) # gv.t without deleted points
  nt = float(len(t))

  gv.dft = numpy.zeros( (gv.ny,gv.nf), dtype=float) # Allocate memory
  w = 2*numpy.pi*numpy.array(gv.f)                  # Angular frequencies
  
  # Transform y values subtracted from mean
  dy = []
  for i in range(0,gv.ny):
    y = numpy.delete( gv.Cy[i], gv.delete ) # gv.Cy without the deleted points
    mean = numpy.mean( y )          # Scalar
    dy.append( y-mean )             # list of lists dim: [gv.ny,nt]

  for k in range(0,gv.nf):
    C2 = numpy.cos( w[k]*t )           # Array with nt positions
    S2 = numpy.sin( w[k]*t )           # Array with nt positions
    for i in range(0,gv.ny):
      sum1  = numpy.inner(dy[i],C2)    # Inner vector product between dy and C2
      sum2  = numpy.inner(dy[i],S2)    # Inner vector product between dy and C2
      gv.dft[i][k] = 2.0*numpy.hypot(sum1,sum2)/nt # Scalar




#-------------------------------------------------------------------------------
def shiftControlHold(event):
  """
  Save the information whether the <shif> and <control> keys are hold or not
  in the GlobalVariables class to be used by the specific tasks in control()
  """
  if event.key == "shift":
    if event.name == "key_press_event":      gv.shiftHold = True
    elif event.name == "key_release_event":  gv.shiftHold = False
  elif event.key == "control":
    if event.name == "key_press_event":      gv.controlHold = True
    elif event.name == "key_release_event":  gv.controlHold = False




#-------------------------------------------------------------------------------
def control(event):
  """
  Controls the plot via user keyboard inputs.
  Every time the keyboard is pressed, this function is called.
  """
  bar="------------------------------------------------------------------"
  semibar="::::::::"
  key = event.key

  #-----------------------------------------------------------------------------
  # Help
  if key=="h":
    print bar
    print "Qview help:"
    print ""
    print "[C]  Means Ctrl key."
    print "[S]  Means Shift key."
    print "[>]  Means right arrow."
    print "[<]  Means left arrow."
#    print "[^]  Means up arrow."
#    print "[v]  Means down arrow."
    print ""
    print semibar,"General Options"
    print "h      : Print this help."
    print "i      : Display image of the point over which the cursor is."
    print "q      : Quit."
    print "s      : Save the data as it is shown."
    print "p      : Print cursor position."
    print ""
    print semibar,"Plotting Options"
    print "e      : Replot the data without reading the data file again."
    print "g      : Show/Hide the grid."
    print "r      : Read the data again and replot."
    print "t      : Calculate DFT again and replot it."
    print ""
    print semibar,"Point marking Options"
    print "d      : Delete/Mark point."
    print "[C][d] : Delete/Mark point without redrawing all plot (faster)."
    print "u      : Undelete/unmark point."
    print "[C][u] : Undelete/Unmark point without redrawing all plot (faster)."
    print ""
    print semibar,"Cursor Options"
    print "[.]    : Move the cursor to the right   1 point."
    print "[C][.] : Move the cursor to the right  10 points."
    print "[S][.] : Move the cursor to the right 100 points."
    print "[,]    : Move the cursor to the left    1 point."
    print "[C][,] : Move the cursor to the left   10 points."
    print "[S][,] : Move the cursor to the left  100 points."
    print "Home   : Cursor to the left of screen."
    print "[C]Home: Cursor to the start of the data."
    print "End    : Cursor to the right of screen."
    print "[C]End : Cursor to the end of the data."
    print ""
    print semibar,"Zoom and scroll Options"
    print "[>]    : X roll right."
    print "[C][>] : Page right in X."
    print "[S][>] : Expand in X."
    print "[<]    : X roll left."
    print "[C][<] : Page left in X."
    print "[S][<] : Condense in X."
    print "BkSp   : Reset roll in X."
    print "[S]BkSp: Reset mag in X."
    print "[C]BkSp: Reset mag & roll in X."
    print bar


  #-----------------------------------------------------------------------------
  # Display image of the point over which the cursor is.
  elif key=="i":
    if gv.figure==1 or gv.figure==2:
      if gv.display!=None:
        gv.display( gv.id, event )
      else:
        print "Run qview with -i option to be able to use \"i\" keystroke."


  #-----------------------------------------------------------------------------
  # Delete/Undelete points
  elif key=="d" or key=="u":
    if gv.figure==1 or gv.figure==2: # Just for 'raw' and 'reduced' plots

      # Delete the point
      if key=="d":
        if gv.id not in gv.delete:
          gv.delete.append(gv.id)
      # Undelete the point
      else:
        if gv.id in gv.delete:
          gv.delete.remove(gv.id)

      # Fast mode: don't replot all the graph just to mark the (un)deleted point
      fast = False
      if gv.controlHold: fast=True     

      if not fast: plotAll(keyEvent=event)    

      # Move the cursor
      if fast    : gv.controlHold=False
      if key=="d":
        gv.id+=1
        gv.CO[gv.axes].onmove(event)
        gv.CE[gv.axes].onmove(event)
      else       :
        gv.id-=1
        gv.CO[gv.axes].onmove(event)
        gv.CE[gv.axes].onmove(event)
      if fast    : gv.controlHold=True


  #-----------------------------------------------------------------------------
  # Replot the data without reading the data file again
  elif key=="e":
    plotAll(keyEvent=event)


  #-----------------------------------------------------------------------------
  # Show grid
  elif key=="g":
    pass # The matplotlib itself shows the grid. We don't need to do anything


  #-----------------------------------------------------------------------------
  # Quit
  elif key=="q":
    sys.exit()


  #-----------------------------------------------------------------------------
  # Replot
  elif key=="r":
    readLightCurveFile()
    plotAll(keyEvent=event)


  #-----------------------------------------------------------------------------
  # Save
  elif key=="s":

    # Write the data of the modified light curve
    # Check if the output file name is valid
    basename=os.path.basename( gv.fileName )
    if gv.ofile==gv.fileName or gv.ofile==basename:
      print "You can't use the input file name. Choose another one!"
    else:
      OFILE = file(gv.ofile,'w')
      for i in range(0,gv.nt):
        # If the point wasn't deleted, save it in the output file
        if i not in gv.delete:
          out = "%s" % gv.tjd[i]
          for j in range(0,gv.ny):
            out += "  %.10f" % gv.Cy[j][i]
          OFILE.write(out+"\n")
      OFILE.close()
      print "Data written to \"%s\"." % gv.ofile


    # Write the data of the discrete fourier transform
    # Check if the output file name is valid
    if gv.odftfile==gv.fileName or gv.odftfile==basename:
      print "You can't use the input file name. Choose another one!"
    else:
      OFILE = file(gv.odftfile,'w')
      for i in range(0,gv.nf):
        out = "%.10f" % gv.f[i]
        for j in range(0,gv.ny):
          out += "  %.10f" % gv.dft[j][i]
        OFILE.write(out+"\n")
      OFILE.close()
      print "Data written to \"%s\"." % gv.odftfile


  #-----------------------------------------------------------------------------
  # Print Cursor position
  elif key=="p":
    px = None
    py = None
    if   gv.figure==1:
      px = gv.CO[gv.axes].fmtx(0)
      py = gv.CO[gv.axes].fmty(0)
    elif gv.figure==2:
      px = gv.CE[gv.axes].fmtx(0)
      py = gv.CE[gv.axes].fmty(0)
    elif gv.figure==3:
      px = gv.CD[gv.axes].fmtx(0)
      py = gv.CD[gv.axes].fmty(0)
    print "x=%s, y=%s" % (px,py)


  #-----------------------------------------------------------------------------
  # Calculate DFT again and replot it
  elif key=="t":
    plotAll(plotDFT=True,keyEvent=event)


  #-----------------------------------------------------------------------------
  # Cursor goes to left
  # If [ctrl] is pressed, moves 10 points
  # If [shift] is pressed, moves 100 points
  elif key==",":
    if not gv.controlHold:
      gv.id -= 1
      gv.CO[gv.axes].onmove(event)
      gv.CE[gv.axes].onmove(event)
      gv.CD[gv.axes].onmove(event)
    else:
      gv.id -= 10
      gv.CO[gv.axes].onmove(event)
      gv.CE[gv.axes].onmove(event)
      gv.CD[gv.axes].onmove(event)
  elif key=="<":  # Shift+, = <
    gv.id -= 100
    gv.CO[gv.axes].onmove(event)
    gv.CE[gv.axes].onmove(event)
    gv.CD[gv.axes].onmove(event)


  #-----------------------------------------------------------------------------
  # Cursor goes to right
  # If [ctrl] is pressed, moves 10 points
  # If [shift] is pressed, moves 100 points
  elif key==".":
    if not gv.controlHold:
      gv.id += 1
      gv.CO[gv.axes].onmove(event)
      gv.CE[gv.axes].onmove(event)
      gv.CD[gv.axes].onmove(event)
    else:
      gv.id += 10
      gv.CO[gv.axes].onmove(event)
      gv.CE[gv.axes].onmove(event)
      gv.CD[gv.axes].onmove(event)
  elif key==">":  # Shift+. = >
    gv.id += 100
    gv.CO[gv.axes].onmove(event)
    gv.CE[gv.axes].onmove(event)
    gv.CD[gv.axes].onmove(event)


  #-----------------------------------------------------------------------------
  # Ignores "control" and "shift" key.
  # shiftContrlHold does the necessary work of keeping track whether they're
  # pressed or not.
  elif key=="control" or key=="shift":
    pass


  #-----------------------------------------------------------------------------
  # X roll right or left     (just arrows)
  # page right or left in X  (arrows with ctrl  key)
  # condense or expand X     (arrows with shift key)
  elif key=="right" or key=="left":
    step = 0.1                   # Changes in 10% steps


    # Changes in time
    if gv.figure==1 or gv.figure==2:
      # Get the limits to update the variables used to set the limits
      # When the user scroll or zoom the graph with the buttons, these variables
      # are changed but gv.tr,gv.tm,gv.fr,gv.fm are not!
      to = gv.t[0]
      tf = gv.t[gv.nt-1]
      Dt = tf-to
      x1,x2 = xlim()
      gv.tr = x1-to
      gv.tm = ( x2 - gv.tr - to )/Dt

      # Expand/ondense
      if gv.shiftHold:
        if key=="right": gv.tm-=step  # Right: expand
        else           : gv.tm+=step  # Left : condense
      # Page right/left in X
      elif gv.controlHold:
        if key=="right": gv.tr=tf-to-gv.tm*Dt  # Page right
        else           : gv.tr=0.0             # Page left
      # Scroll
      else:
        if key=="right": gv.tr+=step*Dt
        else           : gv.tr-=step*Dt

      # Set the limits
      xlim( gv.tr+to, gv.tr+to + gv.tm*Dt )


    # Changes in frequency
    else:
      # Get the limits to update the variables used to set the limits
      # When the user scroll or zoom the graph with the buttons, these variables
      # are changed but gv.tr,gv.tm,gv.fr,gv.fm are not!
      fo = gv.f[0]
      ff = gv.f[gv.nf-1]
      Df = ff-fo
      x1,x2 = xlim()
      gv.fr = x1-gv.t[0]
      gv.fm = ( x2 - gv.fr - fo )/Df

      # Expand/ondense
      if gv.shiftHold:
        if key=="right": gv.fm-=step  # Right: expand
        else           : gv.fm+=step  # Left : condense
      # Page right/left in X
      elif gv.controlHold:
        if key=="right": gv.fr=ff-fo-gv.fm*Df  # Page right
        else           : gv.fr=0.0             # Page left
      # Scroll
      else:
        if key=="right": gv.fr+=step*Df
        else           : gv.fr-=step*Df

      # Set the limits
      xlim( gv.fr+fo, gv.fr+fo + gv.fm*Df )

    plotAll(keyEvent=event)


  #-----------------------------------------------------------------------------
  # Cursor to the left of screen or (with ctrl) to the start of data
  elif key=="home":
    if gv.controlHold: # Start of data
      gv.id=0
      gv.CO[gv.axes].onmove(event)
      gv.CE[gv.axes].onmove(event)
      gv.CD[gv.axes].onmove(event)
    else:              # Start of screen
      # Find the id of the first point visible on the screen
      if gv.figure==1 or gv.figure==2:
        figure(2)
        v = axis()
        gv.id = numpy.searchsorted(gv.t, v[0])
      else:
        figure(3)
        v = axis()
        gv.id = numpy.searchsorted(gv.f, v[0])
      # And move the cursor to it
      gv.CO[gv.axes].onmove(event)
      gv.CE[gv.axes].onmove(event)
      gv.CD[gv.axes].onmove(event)


  #-----------------------------------------------------------------------------
  # Cursor to the right of screen or (with ctrl) to the end of data
  elif key=="end":
    if gv.controlHold: # End of data
      if gv.figure==1 or gv.figure==2: gv.id=gv.nt-1
      else                           : gv.id=gv.nf-1
      gv.CO[gv.axes].onmove(event)
      gv.CE[gv.axes].onmove(event)
      gv.CD[gv.axes].onmove(event)
    else:              # Start of screen
      # Find the id of the first point visible on the screen
      if gv.figure==1 or gv.figure==2:
        figure(2)
        v = axis()
        gv.id = numpy.searchsorted(gv.t, v[1]) - 1
      else:
        figure(3)
        v = axis()
        gv.id = numpy.searchsorted(gv.f, v[1]) - 1
      # And move the cursor to it
      gv.CO[gv.axes].onmove(event)
      gv.CE[gv.axes].onmove(event)
      gv.CD[gv.axes].onmove(event)


  #-----------------------------------------------------------------------------
  # BkSp         reset roll in X
  # Shift-BkSp   reset mag in X
  # Ctrl-BkSp    reset mag & roll in X
  elif key=="backspace":
    if gv.figure==1 or gv.figure==2:
      if gv.controlHold:
        gv.tr = 0.0
        gv.tm = 1.0
      elif gv.shiftHold:
        gv.tm = 1.0
      else:
        gv.tr = 0.0
    else:
      if gv.controlHold:
        gv.fr = 0.0
        gv.fm = 1.0
      elif gv.shiftHold:
        gv.fm = 1.0
      else:
        gv.fr = 0.0
    plotAll(keyEvent=event)

    
  #-----------------------------------------------------------------------------
  # "down" key stops the program! I don't know why not how to avoid it!
  elif key=="down":
    print event
    print "\"down\" key stops the program! I don't know why!"


  #-----------------------------------------------------------------------------
  # Unknown option
  else:
    print "There is no option \"%s\"." % key

